package com.uobgroup.ews.uam.core.service;

import java.util.Iterator;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.uobgroup.ews.uam.core.dao.AccessControlDao;
import com.uobgroup.ews.uam.core.dao.CombinationACLDao;
import com.uobgroup.ews.uam.core.dao.CombinationMatrixDao;
import com.uobgroup.ews.uam.core.dao.SecurityGroupDao;
import com.uobgroup.ews.uam.core.domain.AccessControl;
import com.uobgroup.ews.uam.core.domain.CombinationACL;
import com.uobgroup.ews.uam.core.domain.CombinationMatrix;
import com.uobgroup.ews.uam.core.domain.CombinationType;
import com.uobgroup.ews.uam.core.domain.SecurityGroup;

@Service
@Transactional
public class AccessControlServiceImpl implements AccessControlService {

   @Autowired
   AccessControlDao accessControlDao;

   @Autowired
   CombinationMatrixDao combinationMatrixDao;

   @Autowired
   CombinationMatrixService combinationMatrixService;

   @Autowired
   CombinationACLDao combinationACLDao;

   @Autowired
   SecurityGroupDao securityGroupDAO;

   public long countAllAccessControls() {
      return accessControlDao.count();
   }

   /*
    * Phuong Tran
    */
   public void deleteAccessControl(AccessControl accessControl) {
      String userId = accessControl.getLastModificationUserId();
      if (!accessControlDao.checkTheAssociationWithRoleSubType(accessControl.getId())) {
         List<CombinationACL> combinationACLs = accessControl.getCombinations();
         accessControlDao.updateUserIdAndDelete(AccessControl.class, accessControl.getId(),
               userId);
         for(CombinationACL acl : combinationACLs){
            combinationMatrixDao.updateUserIdAndDelete(CombinationACL.class, acl.getId(), userId);
         }
      }
   }

   public AccessControl findAccessControl(Long id) {
      return accessControlDao.findOne(id);
   }

   public List<AccessControl> findAllAccessControls() {
      return accessControlDao.findAll();
   }

   public List<AccessControl> findAccessControlEntries(int firstResult, int maxResults) {
      return accessControlDao.findAll(firstResult, maxResults);
   }

   /*
    * Phuong Tran
    */
   public void saveAccessControl(AccessControl accessControl) {
      // accessControl.setModificationDate(new
      // Date(System.currentTimeMillis()));
      accessControlDao.save(accessControl);
      findCombinationsToMakeAssociate(accessControl);
   }

   /*
    * Phuong Tran
    */
   public AccessControl updateAccessControl(AccessControl accessControl) {
      String userId = accessControl.getLastModificationUserId();
      if (!accessControlDao.checkTheAssociationWithRoleSubType(accessControl.getId())) {
         boolean isTypeChange = false;
         AccessControl existingACL = accessControlDao.findOne(accessControl.getId());
         if (existingACL != null) {
            if (!accessControl.getType().toString().equals(existingACL.getType().toString())) {
               // type was changed
               existingACL.setType(accessControl.getType());
               List<CombinationACL> combinationACLs = existingACL.getCombinations();
               for (CombinationACL acl : combinationACLs) {
                  acl.setLastModificationUserId(userId);
               }
               // remove CombinationACLs
               combinationMatrixDao.removeCombinationACLs(combinationACLs);
               isTypeChange = true;
            }
         }

         // accessControl.setModificationDate(new
         // Date(System.currentTimeMillis()));
         AccessControl updatedEntity = accessControlDao.update(accessControl);

         if (isTypeChange) {
            findCombinationsToMakeAssociate(updatedEntity);
         }
         else {
            updateSecurityGroup(updatedEntity);
         }

         return updatedEntity;
      }
      else {
         return null;
      }
   }

   public List<AccessControl> findAccessControlbyLikeName(String accessControlName) {
      List<AccessControl> accessControls = accessControlDao.findByLikeName(accessControlName);
      return accessControls;
   }

   public List<AccessControl> findAllAccessControlsbyInIds(List<Long> ids) {
      List<AccessControl> accessControls = accessControlDao.findByIds(ids);
      return accessControls;
   }

   /*
    * Phuong Tran
    */
   public void findCombinationsToMakeAssociate(AccessControl accessControl) {
      // build security groups from this ACL with combinations that have
      // the same type
      String userId = accessControl.getLastModificationUserId();
      CombinationType combinationType = accessControl.getType();
      List<CombinationMatrix> combinations = combinationMatrixDao.findCombinationsByType(combinationType.ordinal());
      Iterator<CombinationMatrix> it = combinations.iterator();
      while (it.hasNext()) {
         CombinationMatrix combination = it.next();
         combination.setLastModificationUserId(userId);
         SecurityGroup securityGroup = combinationMatrixService.buildSecurityGroup(combination, accessControl);
         if (securityGroup != null) {
            securityGroup.setLastModificationUserId(userId);
            combinationMatrixService.buildCombinationACL(combination, accessControl, securityGroup);
         }
      }
   }

   /*
    * Phuong Tran
    */
   @Override
   public List<String> findAllACLName() {
      return accessControlDao.findAllACLName();
   }

   /*
    * (non-Javadoc)
    * 
    * @see
    * com.uobgroup.ews.uam.core.service.AccessControlService#isACLInUse(java
    * .lang.Long)
    */
   @Override
   public boolean isACLInUse(Long Id) {
      return accessControlDao.checkTheAssociationWithRoleSubType(Id);
   }

   /*
    * Phuong Tran
    */
   private void updateSecurityGroup(AccessControl acl) {
      String userId = acl.getLastModificationUserId();
      List<CombinationMatrix> lstCombinations = combinationACLDao.findCombinations(acl);
      if (lstCombinations != null) {
         Iterator<CombinationMatrix> it = lstCombinations.iterator();
         while (it.hasNext()) {
            CombinationMatrix combi = it.next();
            combi.setLastModificationUserId(userId);
            SecurityGroup secGroup = combinationACLDao.findSecGroup(combi, acl);
            if (secGroup != null) {
               String secName = combinationMatrixService.buildSecGroupName(combi, acl);
               secGroup.setDisplayName(secName);
               secGroup.setLastModificationUserId(userId);
               securityGroupDAO.update(secGroup);
            }
         }
      }
   }

}